/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package javaapplication1;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author new
 */
public class Reallocation {

    public void reallocate(String fileName) throws FileNotFoundException, IOException{
        ArrayList usedLocation = new ArrayList();
        int location = 0;
        int length = 0;
        Pattern pattern;
        Matcher matcher;
        String tempFile = "ReallcateTemp";
        FileHandler fh = new FileHandler();
        BufferedReader br = fh.openReadFile(fileName);
        BufferedWriter bw = fh.openWriteFile(tempFile);
        HashMap hmLength = new HashMap();
        HashMap hmMnemonic = new HashMap();
        HashMap hmLabel = new HashMap();
        ArrayList alMnemonic = new ArrayList();
        DBHandler dbh = new DBHandler();
        NumberHandler nh = new NumberHandler();

        String tempStr = br.readLine();
        MnemonicHandler mh = new MnemonicHandler();
        while(tempStr != null){

            if(tempStr.contains("CSEG")){
                pattern = Pattern.compile("(?<=\\s{0,65535})\\w*");
                matcher = pattern.matcher(tempStr.substring(tempStr.indexOf("CSEG") + 4));
                if(matcher.find()){
                    location = Integer.valueOf(nh.toHex(matcher.group()), 16);
                    tempStr = tempStr.substring(tempStr.indexOf(matcher.group()) + matcher.group().length());
                } else {
                    System.out.println("CSEG should have an address.");
                    System.exit(0);
                }
                while(true){
                    if(tempStr == null){
                        System.out.println("CSEG should have an END!");
                        System.exit(0);
                    }
                    if(tempStr.contains(":")){
                        pattern = Pattern.compile("\\w*(?=\\s{0,65536}:)");
                        matcher = pattern.matcher(tempStr);
                        matcher.find();
                        hmLabel.put(matcher.group(), location + length);
                    }
                    if(tempStr.contains("ORG") || tempStr.contains("RSEG") || tempStr.contains("CSEG")){
                        System.out.println("CSEG should have an END.");
                        System.exit(0);
                    }
                    if(tempStr.contains("END")){
                        if(length == 0){
                            break;
                        } else {
                            hmLength.put(location, length);
                            hmMnemonic.put(location, alMnemonic);
                            usedLocation.add(location);
                            location += length;
                            length = 0;
                            alMnemonic.clear();
                            tempStr = tempStr.substring(tempStr.indexOf("END") + 3);
                            break;
                        }
                    }
                    if(tempStr.contains("DB")){
                        alMnemonic.add(tempStr);
                        length += dbh.countLength(tempStr);
                        tempStr = br.readLine();
                        continue;
                    }
                    alMnemonic.add(tempStr);
                    length += mh.countLength(tempStr);
                    tempStr = br.readLine();
                }
                continue;
            }

            if(tempStr.contains("ORG")){
                pattern = Pattern.compile("(?<=\\s{0,65535})\\w*");
                matcher = pattern.matcher(tempStr.substring(tempStr.indexOf("ORG") + 3));
                if(matcher.find()){
                    location = Integer.valueOf(nh.toHex(matcher.group()), 16);
                    tempStr = tempStr.substring(tempStr.indexOf(matcher.group()) + matcher.group().length());
                } else {
                    System.out.println("ORG should have an address.");
                    System.exit(0);
                }
                while(true){
                    if(tempStr == null){
                        if(length == 0){
                           break;
                        }
                        hmLength.put(location, length);
                        hmMnemonic.put(location, alMnemonic);
                        usedLocation.add(location);
                        location += length;
                        length = 0;
                        alMnemonic.clear();
                        break;
                    }
                    if(tempStr.contains("ORG") || tempStr.contains("CSEG") || tempStr.contains("RSEG")){
                        if(length == 0){
                            break;
                        }
                        hmLength.put(location, length);
                        hmMnemonic.put(location, alMnemonic);
                        usedLocation.add(location);
                        location += length;
                        length = 0;
                        alMnemonic.clear();
                        break;
                    }
                    if(tempStr.contains(":")){
                        pattern = Pattern.compile("\\w*(?=\\s{0,65536}:)");
                        matcher = pattern.matcher(tempStr);
                        matcher.find();
                        hmLabel.put(matcher.group(), location + length);
                    }
                    if(tempStr.contains("END")){
                        System.out.println("ORG cannot have an END.");
                        System.exit(0);
                    }
                    if(tempStr.contains("DB")){
                        alMnemonic.add(tempStr);
                        length += dbh.countLength(tempStr);
                        tempStr = br.readLine();
                        continue;
                    }
                    alMnemonic.add(tempStr);
                    length += mh.countLength(tempStr);
                    tempStr = br.readLine();
                }
                continue;
            }

            if(tempStr.contains("RSEG")){
                String temp = new String();
                String rsegLabel = new String();
                pattern = Pattern.compile("(?<=\\s{0,65535})\\w*");
                matcher = pattern.matcher(tempStr.substring(tempStr.indexOf("RSEG") + 4));
                if(matcher.find()){
                    rsegLabel = matcher.group();
                    tempStr = tempStr.substring(tempStr.indexOf(rsegLabel) + rsegLabel.length());
                    int i = LabelHandler.segTable.indexOf(rsegLabel);
                    temp = (String) LabelHandler.segInfoTable.get(i);
                    if(temp.contains("PAGE")){
                        location = ((location / 2048) + 1) * 2048;
                    }
                }
                while(true){
                    if(tempStr == null){
                        System.out.println("RSEG should have an END.");
                        System.exit(0);
                    }
                    if(tempStr.contains(":")){
                        pattern = Pattern.compile("\\w*(?=\\s{0,65536}:)");
                        matcher = pattern.matcher(tempStr);
                        matcher.find();
                        hmLabel.put(matcher.group(), location + length);
                    }
                    if(tempStr.contains("CSEG")){
                        System.out.println("RSEG block should not have a CSEG.");
                        System.exit(0);
                    }
                    if(tempStr.contains("ORG")){
                        System.out.println("RSEG block should not have a ORG.");
                        System.exit(0);
                    }
                    if(tempStr.contains("RSEG")){
                        System.out.println("RSEG block should not have anohter RSEG.");
                        System.exit(0);
                    }
                    if(tempStr.contains("END")){
                        if(length == 0){
                            break;
                        }
                        hmLength.put(location, length);
                        hmMnemonic.put(location, alMnemonic);
                        hmLabel.put(rsegLabel, location);
                        usedLocation.add(location);
                        if(temp.contains("INPAGE") && (length > 2048)){
                            System.out.println("RSEG segment large than one page.");
                            System.exit(0);
                        }
                        if(temp.contains("INBLOCK") && (length > 256)){
                            System.out.println("RSEG segment large than one block.");
                            System.exit(0);
                        }
                        location += length;
                        length = 0;
                        alMnemonic.clear();
                        tempStr = tempStr.substring(tempStr.indexOf("END") + 3);
                        break;
                    }
                    if(tempStr.contains("DB")){
                        alMnemonic.add(tempStr);
                        length += dbh.countLength(tempStr);
                        tempStr = br.readLine();
                        continue;
                    }
                    alMnemonic.add(tempStr);
                    length += mh.countLength(tempStr);
                    tempStr = br.readLine();
                }
                continue;
            }
            while(true){
                if(tempStr == null){
                    if(length == 0){
                        break;
                    }
                    hmLength.put(location, length);
                    hmMnemonic.put(location, alMnemonic);
                    usedLocation.add(location);
                    location += length;
                    length = 0;
                    alMnemonic.clear();
                    break;
                }
                if(tempStr.contains("ORG") || tempStr.contains("CSEG") || tempStr.contains("RSEG")){
                    if(length == 0){
                        break;
                    }
                    hmLength.put(location, length);
                    hmMnemonic.put(location, alMnemonic);
                    usedLocation.add(location);
                    location += length;
                    length = 0;
                    alMnemonic.clear();
                    break;
                }
                if(tempStr.contains(":")){
                        pattern = Pattern.compile("\\w*(?=\\s{0,65536}:)");
                        matcher = pattern.matcher(tempStr);
                        matcher.find();
                        hmLabel.put(matcher.group(), location + length);
                }
                if(tempStr.contains("END")){
                    System.out.println("Useless END.");
                    System.exit(0);
                }
                if(tempStr.contains("DB")){
                    alMnemonic.add(tempStr);
                    length += dbh.countLength(tempStr);
                    tempStr = br.readLine();
                    continue;
                }
                alMnemonic.add(tempStr);
                length += mh.countLength(tempStr);
                tempStr = br.readLine();
            }
        }

        length = usedLocation.size();
        Integer[] used = new Integer[length];
        used = (Integer[]) usedLocation.toArray(used);

        for(int i = 0; i < length; i++){
            for(int j = 0; j < length; j++){
                if(used[i] < used[j]){
                    Integer temp = used[i];
                    used[i] = used[j];
                    used[j] = temp;
                }
            }
        }
        usedLocation = new ArrayList();
        for(int i = 0; i < length; i++){
            usedLocation.add(used[i]);

        }

        for(int i = 0; i < length; i++){

            if(i != length -1){
                if((Integer)usedLocation.get(i) + (Integer)hmLength.get(usedLocation.get(i)) > (Integer)usedLocation.get(i + 1)){
                    System.out.println("Block too big.");
                    System.exit(0);
                }
            } else {
                if((Integer)usedLocation.get(i) + (Integer)hmLength.get(usedLocation.get(i)) > 65536){
                    System.out.println("Block too big.");
                    System.exit(0);
                }
            }
        }

        fh.closeReadFile(br);

        br = fh.openReadFile(fileName);
        tempStr = br.readLine();
        if(!(tempStr.contains("CSEG") || tempStr.contains("RSEG") || tempStr.contains("ORG"))){
            bw.append("at 0000");
            bw.newLine();
        }
        while(tempStr != null){
            if(tempStr.contains("CSEG")){
                pattern = Pattern.compile("(?<=\\s{0,65535})\\w*");
                matcher = pattern.matcher(tempStr.substring(tempStr.indexOf("CSEG") + 4));
                if(matcher.find()){
                    String locationTemp = nh.toHex(matcher.group());
                    while(locationTemp.length() < 4){
                        locationTemp = "0" + locationTemp;
                    }
                    bw.append("at "+ locationTemp);
                    bw.newLine();
                    tempStr = tempStr.substring(tempStr.indexOf(matcher.group()) + matcher.group().length());
                }
            }
            if(tempStr.contains("ORG")){
                pattern = Pattern.compile("(?<=\\s{0,65535})\\w*");
                matcher = pattern.matcher(tempStr.substring(tempStr.indexOf("ORG") + 3));
                if(matcher.find()){
                    String locationTemp = nh.toHex(matcher.group());
                    while(locationTemp.length() < 4){
                        locationTemp = "0" + locationTemp;
                    }
                    bw.append("at "+ locationTemp);
                    bw.newLine();
                    tempStr = tempStr.substring(tempStr.indexOf(matcher.group()) + matcher.group().length());
                }
            }
            if(tempStr.contains("RSEG")){
                pattern = Pattern.compile("(?<=\\s{0,65535})\\w*");
                matcher = pattern.matcher(tempStr.substring(tempStr.indexOf("RSEG") + 4));
                if(matcher.find()){
                    String locationTemp = nh.toHex("" + hmLabel.get(matcher.group()));
                    while(locationTemp.length() < 4){
                        locationTemp = "0" + locationTemp;
                    }
                    bw.append("at "+ locationTemp);
                    bw.newLine();
                    tempStr = tempStr.substring(tempStr.indexOf(matcher.group()) + matcher.group().length());
                }
            }
            if(tempStr.contains("END")){
                tempStr = tempStr.substring(tempStr.indexOf("END") + 3);
            }
            if(tempStr.contains(":")){
                tempStr = tempStr.substring(tempStr.indexOf(":") + 1);
            }
            length = LabelHandler.segTable.size();
            for(int i = 0; i < length; i++){
                if(tempStr.contains((CharSequence) LabelHandler.segTable.get(i))){
                    tempStr.replaceAll("" + LabelHandler.segTable.get(i),"" +  hmLabel.get(LabelHandler.segTable.get(i)));
                }
            }
            length = LabelHandler.labelTable.size();
            for(int i = 0; i < length; i++){
                if(tempStr.contains((CharSequence) LabelHandler.labelTable.get(i))){
                    tempStr.replaceAll("" + LabelHandler.labelTable.get(i),"" +  hmLabel.get(LabelHandler.labelTable.get(i)));
                }
            }
            bw.append(tempStr);
            bw.newLine();
            tempStr = br.readLine();
        }

        fh.closeReadFile(br);
        fh.closeWriteFile(bw);
        System.gc();
        fh.replaceFile(tempFile, fileName);
    }
}
